/*
 *  CharGen.cpp
 *  initiativeTracker
 *
 *  Created by Sam Jaffe on 5/5/12.
 *  Copyright 2012 WPI. All rights reserved.
 *
 */

#include <iostream>
#include <typeinfo>
#include <xercesc/dom/DOMNode.hpp>
#include "CharGen.h"
#include "reader.h"

NPC* CharGen::remake(NPC* c) {
    NPC* temp = new NPC(c, idn++);
//    temp->setId(idn);
//    idn++;
    count(temp);
    
    return temp;
}

Character* CharGen::createChar() {
    Character* c = nullptr;
    
    std::cout << "Is this a Player, Ally, or Enemy: ";
    std::string inputLine;
    
    while (c == nullptr) {
        switch(readLine()[0]) {        
            case 'P': case 'p':
                c = new PC(idn);
                std::cout << "Creating new Player\n";
                break;
            case 'A' : case 'a':
                c = new NPC(idn, true);
                std::cout << "Creating new Ally\n";
                break;
            case 'E' : case 'e':
                c = new NPC(idn, false);
                std::cout << "Creating new Foe\n";
                break;
            case '\t': case ' ': case '\0':
                continue;
            default:
                std::cout << "Please input in the form" << 
                " of P, A, or E: \n";
                continue;
        }
        
        idn++;
        break;
    }
    
    std::cout << "NAME: ";
    inputLine = readLine();
    c->setName(inputLine);
    
    std::string type(typeid(*c).name());
    if (!type.compare(npc_type)) {
        //UnitManager
        if (storedMobs.count(inputLine) > 0)  {
            c->setId(idn-1);
            count((NPC*) c);
            return c;
        }
        else
            count((NPC*) c);
    }
    else {
        std::cout << "Player Name: ";
        inputLine = readLine();
        ((PC*) c)->setPlayer(inputLine);
        int surge = readInt("Healing Surges");
        ((PC*) c)->setSurgeMax(surge);
        ((PC*) c)->setSurgeLeft(surge);
    }
    
    int hp = readInt("HP");
    c->setHp(hp);
    c->setHp_max(hp);
    
    c->setAc(readInt("AC"));
    c->setFort(readInt("FORT"));
    c->setRef(readInt("REF"));
    c->setWill(readInt("WILL"));
    
    if (!type.compare("NPC")) {
        //Mobfile
        storedMobs.emplace(((NPC*) c)->getShortName(), ((NPC*) c));
    }
    
    return c;
}

void CharGen::account(NPC* c) {
    std::string name = c->getShortName();
    if (mobCounter.count(name) > 0) {
        int i = mobCounter.find(name)->second;
        if (c->getCount() >= i)
            mobCounter.emplace(name, c->getCount()+1);
    }
    else
        mobCounter.emplace(name, 2);
}

void CharGen::count(NPC* c) {
    std::string name = c->getShortName();
    if (mobCounter.count(name) > 0) {
        int i = mobCounter.find(name)->second;
        c->setCount(i);
        mobCounter.emplace(name, i+1);
    }
    else {
        c->setCount(1);
        mobCounter.emplace(name, 2);
    }
}

Character* CharGen::decode(xercesc::DOMNamedNodeMap* map) {
    std::string name = (char*) map->getNamedItem((XMLCh*)"name")->getNodeValue();
    
    std::string type= (char*) map->getNamedItem((XMLCh*)"type")->getNodeValue();
    
    int hp = atoi((char*)map->getNamedItem((XMLCh*)"health")->getNodeValue());
    //Contains hp, max hp
    int main = atoi((char*)map->getNamedItem((XMLCh*)"base")->getNodeValue());
    // Contains dot,count, initiative, dis
    
    int defense = atoi((char*)map->getNamedItem((XMLCh*)"defense")->getNodeValue());
    // Contains ac,fort,ref,will
    
    int status = atoi((char*)map->getNamedItem((XMLCh*)"status")->getNodeValue());
    //Contains bit string of statuses		
    
    int id = atoi((char*)map->getNamedItem((XMLCh*)"id")->getNodeValue());
    
    Character* c;
    if (type == "player") {
        c = new PC(id);
        int pData = atoi((char*)map->getNamedItem((XMLCh*)"player")->
                                 getNodeValue());
        std::string playerName = (char*) map->getNamedItem((XMLCh*) "pname")->getNodeValue();
        ((PC*) c)->setSurgeLeft(pData & 0xFF);
        ((PC*) c)->setSurgeMax((pData >> 8) & 0xFF);
        ((PC*) c)->setTemp((pData >> 16) & 0xFFFF);
    }
    else {
        bool isAllied = (type == "friend");
        c = new NPC(id, isAllied, (main >> 16) & 0xFF);
    }
    
    c->setHp(hp & 0xFFFF);
    c->setHp_max((hp >> 16) & 0xFFFF);
    c->setDot(main & 0xFF);
    c->setWill(defense & 0xFF);
    c->setRef((defense >> 8) & 0xFF);
    c->setFort((defense >> 16) & 0xFF);
    c->setAc((defense >> 24) & 0xFF);
    c->setInit((main >> 8) & 0xFF);
    c->setDis((main >> 24) & 0xFF);
    
    c->decodeStatus(status);
    
    return c;
}
